package com.ssm.reactive.controller;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ZeroCopyHttpOutputMessage;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

import static org.springframework.web.reactive.function.server.ServerResponse.ok;

/**
 * https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-multipart-forms
 * https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-multipart-forms
 */
@Slf4j
@RestController
public class FileController {
    @GetMapping("download")
    public Mono<ServerResponse> download(ServerRequest request) {
        Resource resource = new ClassPathResource("myimage.png");
        return ok()
                .header("Content-Disposition", "attachment; filename=myimage.png")
                .body(BodyInserters.fromResource(resource))
                .switchIfEmpty(Mono.empty());
    }

    // @GetMapping("download")
    public Mono<Void> download(ServerHttpResponse response) throws IOException {
        ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
        response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=myimage.png");
        response.getHeaders().setContentType(MediaType.IMAGE_PNG);
        Resource resource = new ClassPathResource("parallel.png");
        File file = resource.getFile();
        return zeroCopyResponse.writeWith(file, 0, file.length());
    }

    @PostMapping("upload")
    public Mono<String> upload(ChunkParam chunkParam) throws IOException {
        FilePart filePart = chunkParam.getFile();
        log.debug(filePart.filename());

        Path tempFile = Files.createTempFile("test", filePart.filename());

        // 方法一
        AsynchronousFileChannel channel = AsynchronousFileChannel.open(tempFile, StandardOpenOption.WRITE);
        DataBufferUtils.write(filePart.content(), channel, 0).doOnComplete(() -> log.debug("finish")).subscribe();

        // 方法二
        // filePart.transferTo(tempFile.toFile());

        return Mono.just(tempFile.toString());
    }

    @Getter
    @Setter
    @ToString
    static class ChunkParam implements Serializable {
        private static final long serialVersionUID = 1L;

        Long id;

        /**
         * 当前文件块，从 1 开始
         */
        Integer chunkNumber;

        /**
         * 分块大小
         */
        Long chunkSize;

        /**
         * 当前分块大小
         */
        Long currentChunkSize;

        /**
         * 总大小
         */
        Long totalSize;

        /**
         * 文件标识
         */
        String identifier;

        /**
         * 文件名
         */
        String filename;

        /**
         * 相对路径
         */
        String relativePath;

        /**
         * 总块数
         */
        Integer totalChunks;

        /**
         * 文件类型
         */
        String type;

        FilePart file;
        // MultipartFile file;
    }
}
